﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Configuration;
using System.ServiceModel;

namespace SecurityAgent.ObjectSecurity.Client
{
    public class ObjectSecurityAgent
    {
        private static string _applicationKey;
        private static ObjectSecurityServiceReference.ObjectSecurityServiceClient _serviceObjectClient;
        private static FieldSecurityServiceReference.FieldSecurityServiceClient _serviceFieldClient;

        private static ObjectSecurityAgentConfigurationSection _config
        {
            get
            {
                object section = ConfigurationManager.GetSection("ObjectSecurityService");
                return (ObjectSecurityAgentConfigurationSection)section;
            }
        }

        static public ObjectSecurityServiceReference.ObjectSecurityServiceClient ObjectServiceClient
        {
            get
            {
                if (_serviceObjectClient == null)
                {
                    if (String.IsNullOrEmpty(_config.ObjectServiceEndPoint))
                        _serviceObjectClient = new ObjectSecurityServiceReference.ObjectSecurityServiceClient();
                    else
                        _serviceObjectClient = new ObjectSecurityServiceReference.ObjectSecurityServiceClient(_config.ObjectServiceEndPoint);
                }

                return _serviceObjectClient;
            }
        }

        static public FieldSecurityServiceReference.FieldSecurityServiceClient FieldServiceClient
        {
            get
            {
                if (_serviceFieldClient == null)
                {
                    if (String.IsNullOrEmpty(_config.FieldServiceEndPoint))
                        _serviceFieldClient = new FieldSecurityServiceReference.FieldSecurityServiceClient();
                    else
                        _serviceObjectClient = new ObjectSecurityServiceReference.ObjectSecurityServiceClient(_config.FieldServiceEndPoint);

                }

                return _serviceFieldClient;
            }
        }

        private static SASIdentity _sasIdentity;

        public static string CurrentUserToken
        {
            get
            {
                if (_sasIdentity == null)
                {
                    _sasIdentity = (SASIdentity)Thread.CurrentPrincipal.Identity;
                }

                if (_sasIdentity == null)
                    return string.Empty;
                else
                    return _sasIdentity.UserToken;
            }
        }

        
        private static string GetConfigValue(string configValue, string defaultValue)
        {
            if (String.IsNullOrEmpty(configValue))
                return defaultValue;

            return configValue;
        }

        public static string ApplicationKey
        {
            get
            {
                if (String.IsNullOrEmpty(_applicationKey))
                    _applicationKey = _config.ApplicationKey;
                
                return _applicationKey;
            }
            set
            {
                _applicationKey = value; 
            }
        }


        public static string GetObjectSettingValue(string objectName, string setting)
        {
            return GetObjectSettingValue(objectName, setting, CurrentUserToken);
        }

        public static string GetObjectSettingValue(string objectName, string setting, string userToken)
        {
            try
            {
                string value  = ObjectServiceClient.GetObjectSettingValue(ApplicationKey, userToken, objectName, setting);

                return value;
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
        }

        public static string GetObjectSettings(string objectName)
        {
            return GetObjectSettings(objectName, CurrentUserToken);
        }

        public static string GetObjectSettings(string objectName, string userToken)
        {
            try
            {
                string value = ObjectServiceClient.GetObjectSettings(ApplicationKey, userToken, objectName);

                return value;
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
        }

        public static string GetFieldSettingValue(string objectName, string fieldName, string setting)
        {
            return GetFieldSettingValue(objectName, fieldName, setting, CurrentUserToken);
        }

        public static string GetFieldSettingValue(string objectName, string fieldName, string setting, string userToken)
        {
            try
            {
                string value = FieldServiceClient.GetFieldSettingValue(ApplicationKey, userToken, objectName, fieldName, setting);

                return value;
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
        }

        public static string GetFieldSettings(string objectName, string fieldName)
        {
            return GetFieldSettings(objectName, fieldName, CurrentUserToken);
        }

        public static string GetFieldSettings(string objectName, string fieldName, string userToken)
        {
            try
            {
                string value = FieldServiceClient.GetFieldSettings(ApplicationKey, userToken, objectName, fieldName);

                return value;
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
        }


        public static AccessLevel CheckObjectAccess(string objectName)
        {
            return CheckObjectAccess(objectName, CurrentUserToken);
        }

        public static AccessLevel CheckObjectAccess(string objectName, string userToken)
        {
            try
            {
                ObjectClaim oc = ObjectServiceClient.GetObjectClaim(ApplicationKey, userToken, objectName, false);

                if (oc != null) return oc.ObjectAccess;
                else
                    return null;
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
        }

        public static ObjectClaim[] GetClaimsForCategory(string category)
        {
            return GetClaimsForCategory(category, CurrentUserToken);
        }
       
        public static ObjectClaim[] GetClaimsForCategory(string category, string userToken)
        {
            try
            {
                if (String.IsNullOrEmpty(category))
                {
                    return ObjectServiceClient.GetAllObjects(ApplicationKey, userToken, true);
                }
                else
                {
                    return ObjectServiceClient.GetObjectsByCategory(ApplicationKey, userToken, category, true);
                }
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
        }

        public static ObjectClaim[] GetClaims(string userToken)
        {
            return GetClaimsForCategory(String.Empty, userToken);
        }

        public static ObjectClaim[] GetClaims()
        {
            return GetClaimsForCategory(String.Empty, CurrentUserToken);
        }

    }
}
